package com.mega.ebcs.ebcsformatter;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import com.ibm.as400.access.AS400Array;
import com.ibm.as400.access.AS400Bin1;
import com.ibm.as400.access.AS400Bin2;
import com.ibm.as400.access.AS400Bin4;
import com.ibm.as400.access.AS400Bin8;
import com.ibm.as400.access.AS400ByteArray;
import com.ibm.as400.access.AS400Date;
import com.ibm.as400.access.AS400Float4;
import com.ibm.as400.access.AS400Float8;
import com.ibm.as400.access.AS400PackedDecimal;
import com.ibm.as400.access.AS400Text;
import com.ibm.as400.access.AS400ZonedDecimal;
import com.ibm.as400.access.ArrayFieldDescription;
import com.ibm.as400.access.BinaryFieldDescription;
import com.ibm.as400.access.CharacterFieldDescription;
import com.ibm.as400.access.DateFieldDescription;
import com.ibm.as400.access.FieldDescription;
import com.ibm.as400.access.FloatFieldDescription;
import com.ibm.as400.access.HexFieldDescription;
import com.ibm.as400.access.PackedDecimalFieldDescription;
import com.ibm.as400.access.Record;
import com.ibm.as400.access.RecordFormat;
import com.ibm.as400.access.ZonedDecimalFieldDescription;
import com.ibm.jtopenlite.Conv;
import com.mega.ebcs.entity.EbcsFormat;
import com.mega.ebcs.entity.EbcsFormatId;
import com.mega.ebcs.service.EbcsService;
import com.mega.ebcs.util.ApplicationContextUtils;
import com.mega.ebcs.util.Constant;

public class FieldFormatter {
	
	public EbcsService ebcsService;
	public FieldFormatter() {
		ebcsService = (EbcsService) ApplicationContextUtils.getApplicationContext().getBean("ebcsService");
	}

	public Record packAsciiToEbcs(String body, Long ebcsTransType, String exchangeType) {
		List<EbcsFormat> listEbcsFormat = ebcsService.findEbcsFormatByEbcsTransType(ebcsTransType, exchangeType);
		int usedLength = 0;

		RecordFormat recordFormat = getRecordFormatter(listEbcsFormat);
		Record record = new Record(recordFormat);
		for (EbcsFormat ebcsFormat : listEbcsFormat) {
			record.setField(String.valueOf(ebcsFormat.getId()), asciiToEbcdicField(body.substring(usedLength, usedLength + getLength(ebcsFormat.getLength(), ebcsFormat.getType())), ebcsFormat.getType())); // need
			usedLength = usedLength + getLength(ebcsFormat.getLength(), ebcsFormat.getType());
		}
		return record;
	}

	public String packEbcsToAscii(byte[] data, Long ebcsTransType, String exchangeType) throws UnsupportedEncodingException {
		List<EbcsFormat> listEbcsFormat = ebcsService.findEbcsFormatByEbcsTransType(ebcsTransType, exchangeType);

		RecordFormat recordFormat = getRecordFormatter(listEbcsFormat);
		Record record = recordFormat.getNewRecord(data);

		StringBuilder strMessage = new StringBuilder();

		for (EbcsFormat ebcsFormat : listEbcsFormat) {
			strMessage.append(formatAsciiField(record.getField(ebcsFormat.getId().toString()), ebcsFormat.getType(), ebcsFormat.getLength()));
		}

		return strMessage.toString();
	}

	public void setEbcsField(Record record, String data, EbcsFormat ebcsFormat) {
		record.setField(ebcsFormat.getId(), asciiToEbcdicField(data, ebcsFormat.getType()));
	}
	
	public String getAsciiField(byte[] data, Long ebcsTransType, String exchangeType, String id) throws UnsupportedEncodingException{
		List<EbcsFormat> listEbcsFormat = ebcsService.findEbcsFormatByEbcsTransType(ebcsTransType, exchangeType);
		RecordFormat recordFormat = getRecordFormatter(listEbcsFormat);		
		Record record = recordFormat.getNewRecord(data);
		EbcsFormat ebcsFormat = ebcsService.findEbcsFormatById(new EbcsFormatId(id, exchangeType));
		
		return formatAsciiField(record.getField(id), ebcsFormat.getType(),ebcsFormat.getLength()) ;		
	}
	
	public String formatAsciiField(Object data, String type, Integer length) {
		if (StringUtils.equals(Constant.TYPE_BYTE_ARRAY, type)) {
			return Conv.bytesToHexString((byte[]) data, 0, 4);
		} else {
			return data.toString();
		}
	}

	private RecordFormat getRecordFormatter(List<EbcsFormat> listEbcsFormat) {
		RecordFormat recordFormat = new RecordFormat();
		for (EbcsFormat ebcsFormat : listEbcsFormat) {
			recordFormat.addFieldDescription(getFieldDescription(ebcsFormat));
		}
		return recordFormat;
	}

	private Integer getLength(Integer length, String types) {		
		if (StringUtils.equalsIgnoreCase(Constant.TYPE_BYTE_ARRAY, types)) {
			return length * 2;
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_DATE, types)) {
			return length;
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_DECFLOAT, types)) {
			return length;
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_FLOAT4, types)) {
			return length;
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_FLOAT8, types)) {
			return length;
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_PACKED, types)) {
			return (2 * length) - 1;
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_TEXT, types)) {
			return length;
		} if (StringUtils.equalsIgnoreCase(Constant.TYPE_ZONED, types)) {
			return (2 * length) - 1;
		} else {
			return length;
		}
	}

	private Object asciiToEbcdicField(String data, String types) {
		if (StringUtils.equals(Constant.TYPE_BYTE_ARRAY, types)) {
			return Conv.hexStringToBytes(data);
		} else if (StringUtils.equals(Constant.TYPE_PACKED, types)) {
			return new BigDecimal(data);
		} else if (StringUtils.equals(Constant.TYPE_ZONED, types)) {
			return new BigDecimal(data);
		} else if (StringUtils.equals(Constant.TYPE_TEXT, types)) {
			return new String(data);
		} else if (StringUtils.equals(Constant.TYPE_BIN8, types)) {
			return new Long(data);
		} else if (StringUtils.equals(Constant.TYPE_BIN1, types)) {
			return new Byte(data);
		} else {
			return new Short(data);
		}
	}

	private int getFieldDescriptionPadding(EbcsFormat ebcsFormat) {
		if (StringUtils.equals(Constant.ALIGN_LEFT, ebcsFormat.getPadding()))
			return FieldDescription.ALIGN_LEFT;
		else
			return FieldDescription.ALIGN_RIGHT;
	}

	private FieldDescription getFieldDescription(EbcsFormat ebcsFormat) {
		FieldDescription fd = null;
		if (StringUtils.equalsIgnoreCase(Constant.TYPE_ARRAY, ebcsFormat.getType())) {
			fd = new ArrayFieldDescription(new AS400Array(), String.valueOf(ebcsFormat.getId()));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_BIN1, ebcsFormat.getType())) {
			fd = new BinaryFieldDescription(new AS400Bin1(), String.valueOf(ebcsFormat.getId()));
			fd.setLayoutAttributes(ebcsFormat.getLength(), getFieldDescriptionPadding(ebcsFormat));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_BIN2, ebcsFormat.getType())) {
			fd = new BinaryFieldDescription(new AS400Bin2(), String.valueOf(ebcsFormat.getId()));
			fd.setLayoutAttributes(ebcsFormat.getLength(), getFieldDescriptionPadding(ebcsFormat));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_BIN4, ebcsFormat.getType())) {
			fd = new BinaryFieldDescription(new AS400Bin4(), String.valueOf(ebcsFormat.getId()));
			fd.setLayoutAttributes(ebcsFormat.getLength(), getFieldDescriptionPadding(ebcsFormat));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_BIN8, ebcsFormat.getType())) {
			fd = new BinaryFieldDescription(new AS400Bin8(), String.valueOf(ebcsFormat.getId()));
			fd.setLayoutAttributes(ebcsFormat.getLength(), getFieldDescriptionPadding(ebcsFormat));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_BYTE_ARRAY, ebcsFormat.getType())) {
			fd = new HexFieldDescription(new AS400ByteArray(ebcsFormat.getLength()), String.valueOf(ebcsFormat.getId()));
			fd.setLayoutAttributes(ebcsFormat.getLength(), getFieldDescriptionPadding(ebcsFormat));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_DATE, ebcsFormat.getType())) {
			fd = new DateFieldDescription(new AS400Date(), String.valueOf(ebcsFormat.getId()));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_FLOAT4, ebcsFormat.getType())) {
			fd = new FloatFieldDescription(new AS400Float4(), String.valueOf(ebcsFormat.getId()));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_FLOAT8, ebcsFormat.getType())) {
			fd = new FloatFieldDescription(new AS400Float8(), String.valueOf(ebcsFormat.getId()));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_PACKED, ebcsFormat.getType())) {
			fd = new PackedDecimalFieldDescription(new AS400PackedDecimal((2 * ebcsFormat.getLength()) - 1, 0), ebcsFormat.getId());
			fd.setLayoutAttributes((2 * ebcsFormat.getLength()) - 1, getFieldDescriptionPadding(ebcsFormat));
		}  else if (StringUtils.equalsIgnoreCase(Constant.TYPE_ZONED, ebcsFormat.getType())) {
			fd = new  ZonedDecimalFieldDescription(new AS400ZonedDecimal((2 * ebcsFormat.getLength()) - 1, 0), ebcsFormat.getId());
			fd.setLayoutAttributes((2 * ebcsFormat.getLength()) - 1, getFieldDescriptionPadding(ebcsFormat));
		} else if (StringUtils.equalsIgnoreCase(Constant.TYPE_TEXT, ebcsFormat.getType())) {
			fd = new CharacterFieldDescription(new AS400Text(ebcsFormat.getLength()), ebcsFormat.getId());
			fd.setLayoutAttributes(ebcsFormat.getLength(), getFieldDescriptionPadding(ebcsFormat));
		}
		return fd;
	}
}
